/**
 * Author(session): xuming.Wong <xuming.Wong@gmail.com>
 * Origin source from MaNGOS(GPL2).
 * Copyright (C) 2005-2010 MaNGOS <http://getmangos.com/>
 */

#include "World.h"
#include "Config.h"
#include "SystemConfig.h"
#include "Log.h"
#include "Util.h"
#include "Opcodes.h"
#include "DBCEnums.h"
#include "GridDefine.h"
#include "GameDefine.h"
#include "Player.h"
#include "Weather.h"
#include "VMapFactory.h"
#include "LoginDatabase.h"
#include "CharacterDatabase.h"
#include "WorldDatabase.h"
#include "DBCStores.h"
#include "SqlResultQueue.h"
#include "MapManager.h"
#include "ObjectManager.h"
#include "SpellManager.h"
#include "InstanceSaveManager.h"
#include "ItemEnchantmentManager.h"
#include "PoolManager.h"
#include "GameEventManager.h"
#include "LootManager.h"
#include "SkillManager.h"
#include "AchievementManager.h"
#include "AuctionManager.h"
#include "BattleGroundManager.h"
#include "TicketManager.h"
#include "WaypointManager.h"
#include "CreatureEventAIManager.h"
#include "ScriptManager.h"
#include "CreatureAIRegistry.h"
#include "ObjectAccessor.h"

namespace PQCore
{
	World::World()
		: _playerLimit(0),_allowMovement(true),_shutdownMask(0),_shutdownTimer(0),
		_gameTime(0),_startTime(0),_maxActiveSessionCount(0),_maxQueuedSessionCount(0),
		_resultQueue(0),_nextDailyQuestReset(0),_nextWeeklyQuestReset(0),_scheduledScripts(0),
		_defaultDbcLocale(LOCALE_enUS),_availableDbcLocaleMask(0)
	{
		for(int i = 0; i < CONFIG_UINT32_VALUE_COUNT; ++i){
			_configUInt32Values[i] = 0;
		}

		for(int i = 0; i < CONFIG_INT32_VALUE_COUNT; ++i){
			_configInt32Values[i] = 0;
		}

		for(int i = 0; i < CONFIG_FLOAT_VALUE_COUNT; ++i){
			_configFloatValues[i] = 0.0f;
		}

		for(int i = 0; i < CONFIG_BOOL_VALUE_COUNT; ++i){
			_configBoolValues[i] = false;
		}

	}

	void World::initWorldSetting()
	{
		// Initialize the random number generator
		srand((unsigned int)time(0));
		// Time server startup
		uint32 startTime=getMilliSecondTime();
		
		loadConfigSetting();
		// Init highest guids before any table loading to prevent using not initialized guids in some code.
		SObjectMgr.SetHighestGuids();

		// Check the existence of the map files for all races' startup areas.
		if(!MapManager::ExistMapAndVMap(0,-6240.32f, 331.033f)
			||!MapManager::ExistMapAndVMap(0,-8949.95f,-132.493f)
			||!MapManager::ExistMapAndVMap(0,-8949.95f,-132.493f)
			||!MapManager::ExistMapAndVMap(1,-618.518f,-4251.67f)
			||!MapManager::ExistMapAndVMap(0, 1676.35f, 1677.45f)
			||!MapManager::ExistMapAndVMap(1, 10311.3f, 832.463f)
			||!MapManager::ExistMapAndVMap(1,-2917.58f,-257.98f)
			||_configUInt32Values[CONFIG_UINT32_EXPANSION] && (
			!MapManager::ExistMapAndVMap(530,10349.6f,-6357.29f)
			||!MapManager::ExistMapAndVMap(530,-3961.64f,-13931.2f) ) )
		{
			SLog.outError("Correct *.map files not found in path '%smaps' or *.vmtree/*.vmtile files in '%svmaps'. Please place *.map and vmap files in appropriate directories or correct the DataDir value in the mangosd.conf file.",_dataPath.c_str(),_dataPath.c_str());
			Log::WaitBeforeContinueIfNeed();
			exit(1);
		}

		// Loading strings. Getting no records means core load has to be canceled because no error message can be output.
		SLog.outString();
		SLog.outString("Loading PQCore strings...");
		if (!SObjectMgr.LoadPQCoreStrings()){
			Log::WaitBeforeContinueIfNeed();
			exit(1);// Error message displayed in function already
		}

		// Update the realm entry in the database with the realm type from the config file
		//No SQL injection as values are treated as integers

		// not send custom type REALM_FFA_PVP to realm list
		uint32 server_type = IsFFAPvPRealm() ? REALM_TYPE_PVP : getConfig(CONFIG_UINT32_GAME_TYPE);
		uint32 realm_zone = getConfig(CONFIG_UINT32_REALM_ZONE);
		SLoginDB.PExecute("UPDATE realmlist SET icon = %u, timezone = %u WHERE id = '%d'", server_type, realm_zone, realmID);

		// Remove the bones (they should not exist in DB though) and old corpses after a restart
		SCharacterDB.PExecute("DELETE FROM corpse WHERE corpse_type = '0' OR time < (UNIX_TIMESTAMP()-'%u')", 3*DAY);


		// Load the DBC files
		SLog.outString("Initialize data stores...");
		SDBCStores.LoadDBCStores(_dataPath);
		detectDBCLang();

		SLog.outString( "Loading Script Names...");
		SObjectMgr.LoadScriptNames();

		SLog.outString( "Loading InstanceTemplate..." );
		SObjectMgr.LoadInstanceTemplate();

		SLog.outString( "Loading SkillLineAbilityMultiMap Data..." );
		SSpellMgr.LoadSkillLineAbilityMap();

		// Clean up and pack instances
		SLog.outString( "Cleaning up instances..." );
		// must be called before `creature_respawn`/`gameobject_respawn` tables
		SInstanceSaveMgr.CleanupInstances();

		SLog.outString( "Packing instances..." );
		SInstanceSaveMgr.PackInstances();

		SLog.outString( "Packing groups..." );
		SObjectMgr.PackGroupIds();

		SLog.outString();
		SLog.outString( "Loading Localization strings..." );
		SObjectMgr.LoadCreatureLocales();
		SObjectMgr.LoadGameObjectLocales();
		SObjectMgr.LoadItemLocales();
		SObjectMgr.LoadQuestLocales();
		SObjectMgr.LoadNpcTextLocales();
		SObjectMgr.LoadPageTextLocales();
		SObjectMgr.LoadGossipMenuItemsLocales();
		SObjectMgr.LoadPointOfInterestLocales();
		// Get once for all the locale index of DBC language (console/broadcasts)
		SObjectMgr.SetDBCLocaleIndex(GetDefaultDbcLocale());
		SLog.outString( ">>> Localization strings loaded" );
		SLog.outString();

		SLog.outString( "Loading Page Texts..." );
		SObjectMgr.LoadPageTexts();

		SLog.outString( "Loading Game Object Templates..." );   // must be after LoadPageTexts
		SObjectMgr.LoadGameobjectInfo();

		SLog.outString( "Loading Spell Chain Data..." );
		SSpellMgr.LoadSpellChains();

		SLog.outString( "Loading Spell Elixir types..." );
		SSpellMgr.LoadSpellElixirs();

		SLog.outString( "Loading Spell Learn Skills..." );
		SSpellMgr.LoadSpellLearnSkills();// must be after LoadSpellChains

		SLog.outString( "Loading Spell Learn Spells..." );
		SSpellMgr.LoadSpellLearnSpells();

		SLog.outString( "Loading Spell Proc Event conditions..." );
		SSpellMgr.LoadSpellProcEvents();

		SLog.outString( "Loading Spell Bonus Data..." );
		SSpellMgr.LoadSpellBonuses();// must be after LoadSpellChains

		SLog.outString( "Loading Spell Proc Item Enchant..." );
		SSpellMgr.LoadSpellProcItemEnchant();                   // must be after LoadSpellChains

		SLog.outString( "Loading Aggro Spells Definitions...");
		SSpellMgr.LoadSpellThreats();

		SLog.outString( "Loading NPC Texts..." );
		SObjectMgr.LoadGossipText();

		SLog.outString( "Loading Item Random Enchantments Table..." );
		SItemEnchantmentMgr.LoadRandomEnchantmentsTable();

		SLog.outString( "Loading Items..." );// must be after LoadRandomEnchantmentsTable and LoadPageTexts
		SObjectMgr.LoadItemPrototypes();

		SLog.outString( "Loading Creature Model Based Info Data..." );
		SObjectMgr.LoadCreatureModelInfo();

		SLog.outString( "Loading Equipment templates...");
		SObjectMgr.LoadEquipmentTemplates();

		SLog.outString( "Loading Creature templates..." );
		SObjectMgr.LoadCreatureTemplates();

		SLog.outString( "Loading Creature Model for race..." ); // must be after creature templates
		SObjectMgr.LoadCreatureModelRace();

		SLog.outString( "Loading SpellsScriptTarget...");
		SSpellMgr.LoadSpellScriptTarget();// must be after LoadCreatureTemplates and LoadGameobjectInfo

		SLog.outString( "Loading ItemRequiredTarget...");
		SObjectMgr.LoadItemRequiredTarget();

		SLog.outString( "Loading Reputation Reward Rates...");
		SObjectMgr.LoadReputationRewardRate();

		SLog.outString( "Loading Creature Reputation OnKill Data..." );
		SObjectMgr.LoadReputationOnKill();

		SLog.outString( "Loading Reputation Spillover Data..." );
		SObjectMgr.LoadReputationSpilloverTemplate();

		SLog.outString( "Loading Points Of Interest Data..." );
		SObjectMgr.LoadPointsOfInterest();

		SLog.outString( "Loading Creature Data..." );
		SObjectMgr.LoadCreatures();

		SLog.outString( "Loading pet levelup spells..." );
		SSpellMgr.LoadPetLevelupSpellMap();

		SLog.outString( "Loading pet default spell additional to levelup spells..." );
		SSpellMgr.LoadPetDefaultSpells();

		SLog.outString( "Loading Creature Addon Data..." );
		SLog.outString();
		SObjectMgr.LoadCreatureAddons();                            // must be after LoadCreatureTemplates() and LoadCreatures()
		SLog.outString( ">>> Creature Addon Data loaded" );
		SLog.outString();

		SLog.outString( "Loading Creature Respawn Data..." );   // must be after PackInstances()
		SObjectMgr.LoadCreatureRespawnTimes();

		SLog.outString( "Loading Gameobject Data..." );
		SObjectMgr.LoadGameobjects();

		SLog.outString( "Loading Gameobject Respawn Data..." ); // must be after PackInstances()
		SObjectMgr.LoadGameobjectRespawnTimes();

		SLog.outString( "Loading Objects Pooling Data...");
		SPoolMgr.LoadFromDB();

		SLog.outString( "Loading Game Event Data...");          // must be after SPoolMgr.LoadFromDB for proper load pool events
		SLog.outString();
		SGameEventMgr.LoadFromDB();
		SLog.outString( ">>> Game Event Data loaded" );
		SLog.outString();

		SLog.outString( "Loading Weather Data..." );
		SObjectMgr.LoadWeatherZoneChances();

		SLog.outString( "Loading Quests..." );
		SObjectMgr.LoadQuests();// must be loaded after DBCs, creature_template, item_template, gameobject tables

		SLog.outString( "Loading Quest POI" );
		SObjectMgr.LoadQuestPOI();

		SLog.outString( "Loading Quests Relations..." );
		SLog.outString();
		SObjectMgr.LoadQuestRelations();                            // must be after quest load
		SLog.outString( ">>> Quests Relations loaded" );
		SLog.outString();

		SLog.outString( "Loading UNIT_NPC_FLAG_SPELLCLICK Data..." );
		SObjectMgr.LoadNPCSpellClickSpells();

		SLog.outString( "Loading SpellArea Data..." );          // must be after quest load
		SSpellMgr.LoadSpellAreas();

		SLog.outString( "Loading AreaTrigger definitions..." );
		SObjectMgr.LoadAreaTriggerTeleports();                      // must be after item template load

		SLog.outString( "Loading Quest Area Triggers..." );
		SObjectMgr.LoadQuestAreaTriggers();                         // must be after LoadQuests

		SLog.outString( "Loading Tavern Area Triggers..." );
		SObjectMgr.LoadTavernAreaTriggers();


		SLog.outString( "Loading AreaTrigger script names..." );
		SObjectMgr.LoadAreaTriggerScripts();

		SLog.outString( "Loading event id script names..." );
		SObjectMgr.LoadEventIdScripts();

		SLog.outString( "Loading Graveyard-zone links...");
		SObjectMgr.LoadGraveyardZones();

		SLog.outString( "Loading Spell target coordinates..." );
		SSpellMgr.LoadSpellTargetPositions();

		SLog.outString( "Loading spell pet auras..." );
		SSpellMgr.LoadSpellPetAuras();

		SLog.outString( "Loading Player Create Info & Level Stats..." );
		SLog.outString();
		SObjectMgr.LoadPlayerInfo();
		SLog.outString( ">>> Player Create Info & Level Stats loaded" );
		SLog.outString();

		SLog.outString( "Loading Exploration BaseXP Data..." );
		SObjectMgr.LoadExplorationBaseXP();

		SLog.outString( "Loading Pet Name Parts..." );
		SObjectMgr.LoadPetNames();

		SCharacterDB.CleanDatabase();

		SLog.outString( "Loading the max pet number..." );
		SObjectMgr.LoadPetNumber();

		SLog.outString( "Loading pet level stats..." );
		SObjectMgr.LoadPetLevelInfo();

		SLog.outString( "Loading Player Corpses..." );
		SObjectMgr.LoadCorpses();

		SLog.outString( "Loading Player level dependent mail rewards..." );
		SObjectMgr.LoadMailLevelRewards();

		SLog.outString( "Loading Loot Tables..." );
		SLog.outString();
		SLootMgr.LoadLootTables();
		SLog.outString( ">>> Loot Tables loaded" );
		SLog.outString();

		SLog.outString( "Loading Skill Discovery Table..." );
		SSkillMgr.LoadSkillDiscoveryTable();

		SLog.outString( "Loading Skill Extra Item Table..." );
		SSkillMgr.LoadSkillExtraItemTable();
		
		SLog.outString( "Loading Skill Fishing base level requirements..." );
		SObjectMgr.LoadFishingBaseSkillLevel();

		SLog.outString( "Loading Achievements..." );
		SLog.outString();
		SAchievementMgr.LoadAchievementReferenceList();
		SAchievementMgr.LoadAchievementCriteriaList();
		SAchievementMgr.LoadAchievementCriteriaRequirements();
		SAchievementMgr.LoadRewards();
		SAchievementMgr.LoadRewardLocales();
		SAchievementMgr.LoadCompletedAchievements();
		SLog.outString( ">>> Achievements loaded" );
		SLog.outString();

		// Load dynamic data tables from the database
		SLog.outString( "Loading Auctions..." );
		SLog.outString();
		SAuctionMgr.LoadAuctionItems();
		SAuctionMgr.LoadAuctions();
		SLog.outString( ">>> Auctions loaded" );
		SLog.outString();

		SLog.outString( "Loading Guilds..." );
		SObjectMgr.LoadGuilds();

		SLog.outString( "Loading ArenaTeams..." );
		SObjectMgr.LoadArenaTeams();

		SLog.outString( "Loading Groups..." );
		SObjectMgr.LoadGroups();

		SLog.outString( "Loading ReservedNames..." );
		SObjectMgr.LoadReservedPlayersNames();

		SLog.outString( "Loading GameObjects for quests..." );
		SObjectMgr.LoadGameObjectForQuests();

		SLog.outString( "Loading BattleMasters..." );
		SBattleGroundMgr.LoadBattleMastersEntry();

		SLog.outString( "Loading BattleGround event indexes..." );
		SBattleGroundMgr.LoadBattleEventIndexes();

		SLog.outString( "Loading GameTeleports..." );
		SObjectMgr.LoadGameTele();

		SLog.outString( "Loading Npc Text Id..." );
		SObjectMgr.LoadNpcTextId();                                 // must be after load Creature and NpcText

		SLog.outString( "Loading Gossip scripts..." );
		SObjectMgr.LoadGossipScripts();                             // must be before gossip menu options

		SLog.outString( "Loading Gossip menus..." );
		SObjectMgr.LoadGossipMenu();

		SLog.outString( "Loading Gossip menu options..." );
		SObjectMgr.LoadGossipMenuItems();

		SLog.outString( "Loading Vendors..." );
		SObjectMgr.LoadVendors();                                   // must be after load CreatureTemplate and ItemTemplate

		SLog.outString( "Loading Trainers..." );
		SObjectMgr.LoadTrainerSpell();                              // must be after load CreatureTemplate

		SLog.outString( "Loading Waypoint scripts..." );            // before loading from creature_movement
		SObjectMgr.LoadCreatureMovementScripts();

		SLog.outString( "Loading Waypoints..." );
		SLog.outString();
		SWaypointMgr.Load();

		SLog.outString( "Loading GM tickets...");
		STicketMgr.LoadGMTickets();

		// Handle outdated emails (delete/return)
		SLog.outString( "Returning old mails..." );
		SObjectMgr.ReturnOrDeleteOldMails(false);

		// Load and initialize scripts
		SLog.outString( "Loading Scripts..." );
		SLog.outString();
		SObjectMgr.LoadQuestStartScripts();                         // must be after load Creature/Gameobject(Template/Data) and QuestTemplate
		SObjectMgr.LoadQuestEndScripts();                           // must be after load Creature/Gameobject(Template/Data) and QuestTemplate
		SObjectMgr.LoadSpellScripts();                              // must be after load Creature/Gameobject(Template/Data)
		SObjectMgr.LoadGameObjectScripts();                         // must be after load Creature/Gameobject(Template/Data)
		SObjectMgr.LoadEventScripts();                              // must be after load Creature/Gameobject(Template/Data)
		SLog.outString( ">>> Scripts loaded" );
		SLog.outString();

		SLog.outString( "Loading Scripts text locales..." );    // must be after Load*Scripts calls
		SObjectMgr.LoadDbScriptStrings();

		SLog.outString( "Loading CreatureEventAI Texts...");
		SEventAIMgr.LoadCreatureEventAI_Texts(false);       // false, will checked in LoadCreatureEventAI_Scripts

		SLog.outString( "Loading CreatureEventAI Summons...");
		SEventAIMgr.LoadCreatureEventAI_Summons(false);     // false, will checked in LoadCreatureEventAI_Scripts

		SLog.outString( "Loading CreatureEventAI Scripts...");
		SEventAIMgr.LoadCreatureEventAI_Scripts();

		SLog.outString( "Initializing Scripts..." );
		if(!SScriptMgr.LoadScriptingModule()){
			Log::WaitBeforeContinueIfNeed();
			exit(1);                                            // Error message displayed in function already
		}

		// Initialize game time and timers
		SLog.outString( "DEBUG:: Initialize game time and timers" );
		_gameTime = time(NULL);
		_startTime=_gameTime;

		tm local;
		time_t curr;
		time(&curr);
		local=*(localtime(&curr));                              // dereference and assign
		char isoDate[128];
		sprintf( isoDate, "%04d-%02d-%02d %02d:%02d:%02d",local.tm_year+1900, local.tm_mon+1, local.tm_mday, local.tm_hour, local.tm_min, local.tm_sec);

		SLoginDB.PExecute("INSERT INTO uptime (realmid, starttime, startstring, uptime) VALUES('%u', " UI64FMTD ", '%session', 0)",
			realmID, uint64(_startTime), isoDate);

		_timers[WUPDATE_OBJECTS].SetInterval(0);
		_timers[WUPDATE_SESSIONS].SetInterval(0);
		_timers[WUPDATE_WEATHERS].SetInterval(1*IN_MILLISECONDS);
		_timers[WUPDATE_AUCTIONS].SetInterval(MINUTE*IN_MILLISECONDS);
		_timers[WUPDATE_UPTIME].SetInterval(_configUInt32Values[CONFIG_UINT32_UPTIME_UPDATE]*MINUTE*IN_MILLISECONDS);
																//Update "uptime" table based on configuration entry in minutes.
		_timers[WUPDATE_CORPSES].SetInterval(3*HOUR*IN_MILLISECONDS);
		_timers[WUPDATE_DELETECHARS].SetInterval(DAY*IN_MILLISECONDS); // check for chars to delete every day

		//to set mailtimer to return mails every day between 4 and 5 am
		//mailtimer is increased when updating auctions
		//one second is 1000 -(tested on win system)
		_mailTimer = uint32((((localtime( &_gameTime )->tm_hour + 20) % 24)* HOUR * IN_MILLISECONDS) / _timers[WUPDATE_AUCTIONS].GetInterval() );
																//1440
		_mailTimerExpires = uint32( (DAY * IN_MILLISECONDS) / (_timers[WUPDATE_AUCTIONS].GetInterval()));
		SLog.debugLog("Mail timer set to: %u, mail return is called every %u minutes", _mailTimer, _mailTimerExpires);

		// Initialize static helper structures
		SAIRegistry.Initialize();
		Player::InitVisibleBits();

		// Initialize MapManager
		SLog.outString( "Starting Map System" );
		SMapMgr.Initialize();

		// Initialize Battlegrounds
		SLog.outString( "Starting BattleGround System" );
		SBattleGroundMgr.CreateInitialBattleGrounds();
		SBattleGroundMgr.InitAutomaticArenaPointDistribution();

		//Not sure if this can be moved up in the sequence (with static data loading) as it uses MapManager
		SLog.outString( "Loading Transports..." );
		SMapMgr.LoadTransports();

		SLog.outString("Deleting expired bans..." );
		SLoginDB.Execute("DELETE FROM ip_banned WHERE unbandate<=UNIX_TIMESTAMP() AND unbandate<>bandate");

		SLog.outString("Calculate next daily quest reset time..." );
		InitDailyQuestResetTime();

		SLog.outString("Calculate next weekly quest reset time..." );
		InitWeeklyQuestResetTime();

		SLog.outString("Starting objects Pooling system..." );
		SPoolMgr.Initialize();

		SLog.outString("Starting Game Event system..." );
		uint32 nextGameEvent = SGameEventMgr.Initialize();
		_timers[WUPDATE_EVENTS].SetInterval(nextGameEvent);    //depend on next event

		// Delete all characters which have been deleted X days before
		Player::DeleteOldCharacters();

		SLog.outString( "WORLD: World initialized" );

		uint32 uStartInterval = getMSTimeDiff(startTime, getMilliSecondTime());
		SLog.outString( "SERVER STARTUP TIME: %i minutes %i seconds", uStartInterval / 60000, (uStartInterval % 60000) / 1000 );

	}

	/// Initialize config values
	void World::loadConfigSetting(bool reload)
	{
		if(reload){
			if(SConfig.reload()){
				SLog.outError("World settings reload fail: can't read settings from %session.",SConfig.getFileName().c_str());
				return;
			}
		}
		/// Read the version of the configuration file and warn the user in case of emptiness or mismatch
		uint32 confVersion=SConfig.getIntDefault("ConfVersion",0);
		if(!confVersion){
			SLog.outError("*****************************************************************************");
			SLog.outError(" WARNING: PQ3dCore.conf does not include a ConfVersion variable.");
			SLog.outError("          Your configuration file may be out of date!");
			SLog.outError("*****************************************************************************");
			Log::WaitBeforeContinueIfNeed();
		}else{
			if (confVersion < PQCore_Version){
				SLog.outError("*****************************************************************************");
				SLog.outError(" WARNING: Your mangosd.conf version indicates your conf file is out of date!");
				SLog.outError("          Please check for updates, as your current default values may cause");
				SLog.outError("          unexpected behavior.");
				SLog.outError("*****************************************************************************");
				Log::WaitBeforeContinueIfNeed();
			}
		}

		// Read the player limit and the Message of the day from the config file
		setPlayerLimit(SConfig.getIntDefault("PlayerLimit",DEFAULT_PLAYER_LIMIT),true);
		setDayMsg(SConfig.getStringDefault("DayMsg", "Welcome to the PQ3D world."));

		// Read all rates from the config file
		setConfigPos(CONFIG_FLOAT_RATE_HEALTH, "Rate.Health", 1.0f);
		setConfigPos(CONFIG_FLOAT_RATE_POWER_MANA, "Rate.Mana", 1.0f);
		setConfig(CONFIG_FLOAT_RATE_POWER_RAGE_INCOME, "Rate.Rage.Income", 1.0f);
		setConfigPos(CONFIG_FLOAT_RATE_POWER_RAGE_LOSS, "Rate.Rage.Loss", 1.0f);
		setConfig(CONFIG_FLOAT_RATE_POWER_RUNICPOWER_INCOME, "Rate.RunicPower.Income", 1.0f);
		setConfigPos(CONFIG_FLOAT_RATE_POWER_RUNICPOWER_LOSS,"Rate.RunicPower.Loss",   1.0f);
		setConfig(CONFIG_FLOAT_RATE_POWER_FOCUS,             "Rate.Focus",  1.0f);
		setConfig(CONFIG_FLOAT_RATE_POWER_ENERGY,            "Rate.Energy", 1.0f);
		setConfigPos(CONFIG_FLOAT_RATE_SKILL_DISCOVERY,      "Rate.Skill.Discovery",      1.0f);
		setConfigPos(CONFIG_FLOAT_RATE_DROP_ITEM_POOR,       "Rate.Drop.Item.Poor",       1.0f);
		setConfigPos(CONFIG_FLOAT_RATE_DROP_ITEM_NORMAL,     "Rate.Drop.Item.Normal",     1.0f);
		setConfigPos(CONFIG_FLOAT_RATE_DROP_ITEM_UNCOMMON,   "Rate.Drop.Item.Uncommon",   1.0f);
		setConfigPos(CONFIG_FLOAT_RATE_DROP_ITEM_RARE,       "Rate.Drop.Item.Rare",       1.0f);
		setConfigPos(CONFIG_FLOAT_RATE_DROP_ITEM_EPIC,       "Rate.Drop.Item.Epic",       1.0f);
		setConfigPos(CONFIG_FLOAT_RATE_DROP_ITEM_LEGENDARY,  "Rate.Drop.Item.Legendary",  1.0f);
		setConfigPos(CONFIG_FLOAT_RATE_DROP_ITEM_ARTIFACT,   "Rate.Drop.Item.Artifact",   1.0f);
		setConfigPos(CONFIG_FLOAT_RATE_DROP_ITEM_REFERENCED, "Rate.Drop.Item.Referenced", 1.0f);
		setConfigPos(CONFIG_FLOAT_RATE_DROP_MONEY,           "Rate.Drop.Money", 1.0f);
		setConfig(CONFIG_FLOAT_RATE_XP_KILL,    "Rate.XP.Kill",    1.0f);
		setConfig(CONFIG_FLOAT_RATE_XP_QUEST,   "Rate.XP.Quest",   1.0f);
		setConfig(CONFIG_FLOAT_RATE_XP_EXPLORE, "Rate.XP.Explore", 1.0f);
		setConfig(CONFIG_FLOAT_RATE_REPUTATION_GAIN,           "Rate.Reputation.Gain", 1.0f);
		setConfig(CONFIG_FLOAT_RATE_REPUTATION_LOWLEVEL_KILL,  "Rate.Reputation.LowLevel.Kill", 1.0f);
		setConfig(CONFIG_FLOAT_RATE_REPUTATION_LOWLEVEL_QUEST, "Rate.Reputation.LowLevel.Quest", 1.0f);
		setConfigPos(CONFIG_FLOAT_RATE_CREATURE_NORMAL_DAMAGE,          "Rate.Creature.Normal.Damage", 1.0f);
		setConfigPos(CONFIG_FLOAT_RATE_CREATURE_ELITE_ELITE_DAMAGE,     "Rate.Creature.Elite.Elite.Damage", 1.0f);
		setConfigPos(CONFIG_FLOAT_RATE_CREATURE_ELITE_RAREELITE_DAMAGE, "Rate.Creature.Elite.RAREELITE.Damage", 1.0f);
		setConfigPos(CONFIG_FLOAT_RATE_CREATURE_ELITE_WORLDBOSS_DAMAGE, "Rate.Creature.Elite.WORLDBOSS.Damage", 1.0f);
		setConfigPos(CONFIG_FLOAT_RATE_CREATURE_ELITE_RARE_DAMAGE,      "Rate.Creature.Elite.RARE.Damage", 1.0f);
		setConfigPos(CONFIG_FLOAT_RATE_CREATURE_NORMAL_HP,          "Rate.Creature.Normal.HP", 1.0f);
		setConfigPos(CONFIG_FLOAT_RATE_CREATURE_ELITE_ELITE_HP,     "Rate.Creature.Elite.Elite.HP", 1.0f);
		setConfigPos(CONFIG_FLOAT_RATE_CREATURE_ELITE_RAREELITE_HP, "Rate.Creature.Elite.RAREELITE.HP", 1.0f);
		setConfigPos(CONFIG_FLOAT_RATE_CREATURE_ELITE_WORLDBOSS_HP, "Rate.Creature.Elite.WORLDBOSS.HP", 1.0f);
		setConfigPos(CONFIG_FLOAT_RATE_CREATURE_ELITE_RARE_HP,      "Rate.Creature.Elite.RARE.HP", 1.0f);
		setConfigPos(CONFIG_FLOAT_RATE_CREATURE_NORMAL_SPELLDAMAGE,          "Rate.Creature.Normal.SpellDamage", 1.0f);
		setConfigPos(CONFIG_FLOAT_RATE_CREATURE_ELITE_ELITE_SPELLDAMAGE,     "Rate.Creature.Elite.Elite.SpellDamage", 1.0f);
		setConfigPos(CONFIG_FLOAT_RATE_CREATURE_ELITE_RAREELITE_SPELLDAMAGE, "Rate.Creature.Elite.RAREELITE.SpellDamage", 1.0f);
		setConfigPos(CONFIG_FLOAT_RATE_CREATURE_ELITE_WORLDBOSS_SPELLDAMAGE, "Rate.Creature.Elite.WORLDBOSS.SpellDamage", 1.0f);
		setConfigPos(CONFIG_FLOAT_RATE_CREATURE_ELITE_RARE_SPELLDAMAGE,      "Rate.Creature.Elite.RARE.SpellDamage", 1.0f);
		setConfigPos(CONFIG_FLOAT_RATE_CREATURE_AGGRO, "Rate.Creature.Aggro", 1.0f);
		setConfig(CONFIG_FLOAT_RATE_REST_INGAME,                    "Rate.Rest.InGame", 1.0f);
		setConfig(CONFIG_FLOAT_RATE_REST_OFFLINE_IN_TAVERN_OR_CITY, "Rate.Rest.Offline.InTavernOrCity", 1.0f);
		setConfig(CONFIG_FLOAT_RATE_REST_OFFLINE_IN_WILDERNESS,     "Rate.Rest.Offline.InWilderness", 1.0f);
		setConfigPos(CONFIG_FLOAT_RATE_DAMAGE_FALL,  "Rate.Damage.Fall", 1.0f);
		setConfigPos(CONFIG_FLOAT_RATE_AUCTION_TIME, "Rate.Auction.Time", 1.0f);
		setConfig(CONFIG_FLOAT_RATE_AUCTION_DEPOSIT, "Rate.Auction.Deposit", 1.0f);
		setConfig(CONFIG_FLOAT_RATE_AUCTION_CUT,     "Rate.Auction.Cut", 1.0f);
		setConfigPos(CONFIG_UINT32_AUCTION_DEPOSIT_MIN, "Auction.Deposit.Min", SILVER);
		setConfig(CONFIG_FLOAT_RATE_HONOR, "Rate.Honor",1.0f);
		setConfigPos(CONFIG_FLOAT_RATE_MINING_AMOUNT, "Rate.Mining.Amount", 1.0f);
		setConfigPos(CONFIG_FLOAT_RATE_MINING_NEXT,   "Rate.Mining.Next", 1.0f);
		setConfigPos(CONFIG_FLOAT_RATE_INSTANCE_RESET_TIME, "Rate.InstanceResetTime", 1.0f);
		setConfigPos(CONFIG_FLOAT_RATE_TALENT, "Rate.Talent", 1.0f);
		setConfigPos(CONFIG_FLOAT_RATE_CORPSE_DECAY_LOOTED, "Rate.Corpse.Decay.Looted", 0.0f);

		setConfigMinMax(CONFIG_FLOAT_RATE_TARGET_POS_RECALCULATION_RANGE, "TargetPosRecalculateRange", 1.5f, CONTACT_DISTANCE, ATTACK_DISTANCE);

		setConfigPos(CONFIG_FLOAT_RATE_DURABILITY_LOSS_DAMAGE, "DurabilityLossChance.Damage", 0.5f);
		setConfigPos(CONFIG_FLOAT_RATE_DURABILITY_LOSS_ABSORB, "DurabilityLossChance.Absorb", 0.5f);
		setConfigPos(CONFIG_FLOAT_RATE_DURABILITY_LOSS_PARRY,  "DurabilityLossChance.Parry",  0.05f);
		setConfigPos(CONFIG_FLOAT_RATE_DURABILITY_LOSS_BLOCK,  "DurabilityLossChance.Block",  0.05f);

		setConfigPos(CONFIG_FLOAT_LISTEN_RANGE_SAY,       "ListenRange.Say",       25.0f);
		setConfigPos(CONFIG_FLOAT_LISTEN_RANGE_YELL,      "ListenRange.Yell",     300.0f);
		setConfigPos(CONFIG_FLOAT_LISTEN_RANGE_TEXTEMOTE, "ListenRange.TextEmote", 25.0f);

		setConfigPos(CONFIG_FLOAT_GROUP_XP_DISTANCE, "MaxGroupXPDistance", 74.0f);
		setConfigPos(CONFIG_FLOAT_SIGHT_GUARDER,     "GuarderSight",       50.0f);
		setConfigPos(CONFIG_FLOAT_SIGHT_MONSTER,     "MonsterSight",       50.0f);

		setConfigPos(CONFIG_FLOAT_CREATURE_FAMILY_ASSISTANCE_RADIUS,      "CreatureFamilyAssistanceRadius",     10.0f);
		setConfigPos(CONFIG_FLOAT_CREATURE_FAMILY_FLEE_ASSISTANCE_RADIUS, "CreatureFamilyFleeAssistanceRadius", 30.0f);

		// Read other configuration items from the config file
		setConfigMinMax(CONFIG_UINT32_COMPRESSION, "Compression", 1, 1, 9);
		setConfig(CONFIG_BOOL_ADDON_CHANNEL, "AddonChannel", true);
		setConfig(CONFIG_BOOL_CLEAN_CHARACTER_DB, "CleanCharacterDB", true);
		setConfig(CONFIG_BOOL_GRID_UNLOAD, "GridUnload", true);
		setConfigPos(CONFIG_UINT32_INTERVAL_SAVE, "PlayerSave.Interval", 15 * MINUTE * IN_MILLISECONDS);
		setConfigMinMax(CONFIG_UINT32_MIN_LEVEL_STAT_SAVE, "PlayerSave.Stats.MinLevel", 0, 0, MAX_LEVEL);
		setConfig(CONFIG_BOOL_STATS_SAVE_ONLY_ON_LOGOUT, "PlayerSave.Stats.SaveOnlyOnLogout", true);

		setConfigMin(CONFIG_UINT32_INTERVAL_GRIDCLEAN, "GridCleanUpDelay", 5 * MINUTE * IN_MILLISECONDS, MIN_GRID_DELAY);


		if(reload){
			SMapMgr.setGridCleanUpDelay(getConfig(CONFIG_UINT32_INTERVAL_GRIDCLEAN));
		}

		setConfigMin(CONFIG_UINT32_INTERVAL_MAPUPDATE, "MapUpdateInterval", 100, MIN_MAP_UPDATE_DELAY);
		
		if(reload){
			SMapMgr.setMapUpdateInterval(getConfig(CONFIG_UINT32_INTERVAL_MAPUPDATE));
		}

		setConfig(CONFIG_UINT32_INTERVAL_CHANGEWEATHER, "ChangeWeatherInterval", 10 * MINUTE * IN_MILLISECONDS);

		if (configNoReload(reload, CONFIG_UINT32_PORT_WORLD, "WorldServerPort", DEFAULT_WORLDSERVER_PORT)){
			setConfig(CONFIG_UINT32_PORT_WORLD, "WorldServerPort", DEFAULT_WORLDSERVER_PORT);
		}

		if (configNoReload(reload, CONFIG_UINT32_SOCKET_SELECTTIME, "SocketSelectTime", DEFAULT_SOCKET_SELECT_TIME)){
			setConfig(CONFIG_UINT32_SOCKET_SELECTTIME, "SocketSelectTime", DEFAULT_SOCKET_SELECT_TIME);
		}

		if (configNoReload(reload, CONFIG_UINT32_GAME_TYPE, "GameType", 0)){
			setConfig(CONFIG_UINT32_GAME_TYPE, "GameType", 0);
		}

		if (configNoReload(reload, CONFIG_UINT32_REALM_ZONE, "RealmZone", REALM_ZONE_DEVELOPMENT)){
			setConfig(CONFIG_UINT32_REALM_ZONE, "RealmZone", REALM_ZONE_DEVELOPMENT);
		}

		setConfig(CONFIG_BOOL_ALLOW_TWO_SIDE_ACCOUNTS,            "AllowTwoSide.Accounts", true);
		setConfig(CONFIG_BOOL_ALLOW_TWO_SIDE_INTERACTION_CHAT,    "AllowTwoSide.Interaction.Chat", false);
		setConfig(CONFIG_BOOL_ALLOW_TWO_SIDE_INTERACTION_CHANNEL, "AllowTwoSide.Interaction.Channel", false);
		setConfig(CONFIG_BOOL_ALLOW_TWO_SIDE_INTERACTION_GROUP,   "AllowTwoSide.Interaction.Group", false);
		setConfig(CONFIG_BOOL_ALLOW_TWO_SIDE_INTERACTION_GUILD,   "AllowTwoSide.Interaction.Guild", false);
		setConfig(CONFIG_BOOL_ALLOW_TWO_SIDE_INTERACTION_AUCTION, "AllowTwoSide.Interaction.Auction", false);
		setConfig(CONFIG_BOOL_ALLOW_TWO_SIDE_INTERACTION_MAIL,    "AllowTwoSide.Interaction.Mail", false);
		setConfig(CONFIG_BOOL_ALLOW_TWO_SIDE_WHO_LIST,            "AllowTwoSide.WhoList", false);
		setConfig(CONFIG_BOOL_ALLOW_TWO_SIDE_ADD_FRIEND,          "AllowTwoSide.AddFriend", false);

		setConfig(CONFIG_UINT32_STRICT_PLAYER_NAMES,  "StrictPlayerNames",  0);
		setConfig(CONFIG_UINT32_STRICT_CHARTER_NAMES, "StrictCharterNames", 0);
		setConfig(CONFIG_UINT32_STRICT_PET_NAMES,     "StrictPetNames",     0);

		setConfigMinMax(CONFIG_UINT32_MIN_PLAYER_NAME,  "MinPlayerName",  2, 1, MAX_PLAYER_NAME);
		setConfigMinMax(CONFIG_UINT32_MIN_CHARTER_NAME, "MinCharterName", 2, 1, MAX_CHARTER_NAME);
		setConfigMinMax(CONFIG_UINT32_MIN_PET_NAME,     "MinPetName",     2, 1, MAX_PET_NAME);

		setConfig(CONFIG_UINT32_CHARACTERS_CREATING_DISABLED, "CharactersCreatingDisabled", 0);
		setConfigMinMax(CONFIG_UINT32_CHARACTERS_PER_REALM, "CharactersPerRealm", 10, 1, 10);

		// must be after CONFIG_UINT32_CHARACTERS_PER_REALM
		setConfigMin(CONFIG_UINT32_CHARACTERS_PER_ACCOUNT, "CharactersPerAccount", 50, getConfig(CONFIG_UINT32_CHARACTERS_PER_REALM));

		setConfigMinMax(CONFIG_UINT32_HEROIC_CHARACTERS_PER_REALM, "HeroicCharactersPerRealm", 1, 1, 10);

		setConfig(CONFIG_UINT32_MIN_LEVEL_FOR_HEROIC_CHARACTER_CREATING, "MinLevelForHeroicCharacterCreating", 55);

		setConfigMinMax(CONFIG_UINT32_SKIP_CINEMATICS, "SkipCinematics", 0, 0, 2);

		if (configNoReload(reload, CONFIG_UINT32_MAX_PLAYER_LEVEL, "MaxPlayerLevel", DEFAULT_MAX_LEVEL)){
			setConfigMinMax(CONFIG_UINT32_MAX_PLAYER_LEVEL, "MaxPlayerLevel", DEFAULT_MAX_LEVEL, 1, DEFAULT_MAX_LEVEL);
		}

		setConfigMinMax(CONFIG_UINT32_START_PLAYER_LEVEL, "StartPlayerLevel", 1, 1, getConfig(CONFIG_UINT32_MAX_PLAYER_LEVEL));
		setConfigMinMax(CONFIG_UINT32_START_HEROIC_PLAYER_LEVEL, "StartHeroicPlayerLevel", 55, 1, getConfig(CONFIG_UINT32_MAX_PLAYER_LEVEL));

		setConfigMinMax(CONFIG_UINT32_START_PLAYER_MONEY, "StartPlayerMoney", 0, 0, MAX_MONEY_AMOUNT);

		setConfigPos(CONFIG_UINT32_MAX_HONOR_POINTS, "MaxHonorPoints", 75000);

		setConfigMinMax(CONFIG_UINT32_START_HONOR_POINTS, "StartHonorPoints", 0, 0, getConfig(CONFIG_UINT32_MAX_HONOR_POINTS));

		setConfigPos(CONFIG_UINT32_MAX_ARENA_POINTS, "MaxArenaPoints", 5000);

		setConfigMinMax(CONFIG_UINT32_START_ARENA_POINTS, "StartArenaPoints", 0, 0, getConfig(CONFIG_UINT32_MAX_ARENA_POINTS));

		setConfig(CONFIG_BOOL_ALL_TAXI_PATHS, "AllFlightPaths", false);

		setConfig(CONFIG_BOOL_INSTANCE_IGNORE_LEVEL, "Instance.IgnoreLevel", false);
		setConfig(CONFIG_BOOL_INSTANCE_IGNORE_RAID,  "Instance.IgnoreRaid", false);

		setConfig(CONFIG_BOOL_CAST_UNSTUCK, "CastUnstuck", true);
		setConfig(CONFIG_UINT32_MAX_SPELL_CASTS_IN_CHAIN, "MaxSpellCastsInChain", 10);
		setConfig(CONFIG_UINT32_INSTANCE_RESET_TIME_HOUR, "Instance.ResetTimeHour", 4);
		setConfig(CONFIG_UINT32_INSTANCE_UNLOAD_DELAY,    "Instance.UnloadDelay", 30 * MINUTE * IN_MILLISECONDS);

		setConfig(CONFIG_UINT32_MAX_PRIMARY_TRADE_SKILL, "MaxPrimaryTradeSkill", 2);
		setConfigMinMax(CONFIG_UINT32_MIN_PETITION_SIGNS, "MinPetitionSigns", 9, 0, 9);

		setConfig(CONFIG_UINT32_GM_LOGIN_STATE,    "GM.LoginState",    2);
		setConfig(CONFIG_UINT32_GM_VISIBLE_STATE,  "GM.Visible",       2);
		setConfig(CONFIG_UINT32_GM_ACCEPT_TICKETS, "GM.AcceptTickets", 2);
		setConfig(CONFIG_UINT32_GM_CHAT,           "GM.Chat",          2);
		setConfig(CONFIG_UINT32_GM_WISPERING_TO,   "GM.WhisperingTo",  2);

		setConfig(CONFIG_UINT32_GM_LEVEL_IN_GM_LIST,  "GM.InGMList.Level",  SEC_ADMINISTRATOR);
		setConfig(CONFIG_UINT32_GM_LEVEL_IN_WHO_LIST, "GM.InWhoList.Level", SEC_ADMINISTRATOR);
		setConfig(CONFIG_BOOL_GM_LOG_TRADE,           "GM.LogTrade", false);

		setConfigMinMax(CONFIG_UINT32_START_GM_LEVEL, "GM.StartLevel", 1, getConfig(CONFIG_UINT32_START_PLAYER_LEVEL), MAX_LEVEL);
		setConfig(CONFIG_BOOL_GM_LOWER_SECURITY, "GM.LowerSecurity", false);
		setConfig(CONFIG_BOOL_GM_ALLOW_ACHIEVEMENT_GAINS, "GM.AllowAchievementGain", true);

		setConfig(CONFIG_UINT32_GROUP_VISIBILITY, "Visibility.GroupMode", 0);

		setConfig(CONFIG_UINT32_MAIL_DELIVERY_DELAY, "MailDeliveryDelay", HOUR);

		setConfigPos(CONFIG_UINT32_UPTIME_UPDATE, "UpdateUptimeInterval", 10);

		if (reload){
			_timers[WUPDATE_UPTIME].SetInterval(getConfig(CONFIG_UINT32_UPTIME_UPDATE)*MINUTE*IN_MILLISECONDS);
			_timers[WUPDATE_UPTIME].Reset();
		}

		setConfig(CONFIG_UINT32_SKILL_CHANCE_ORANGE, "SkillChance.Orange", 100);
		setConfig(CONFIG_UINT32_SKILL_CHANCE_YELLOW, "SkillChance.Yellow", 75);
		setConfig(CONFIG_UINT32_SKILL_CHANCE_GREEN,  "SkillChance.Green",  25);
		setConfig(CONFIG_UINT32_SKILL_CHANCE_GREY,   "SkillChance.Grey",   0);

		setConfigPos(CONFIG_UINT32_SKILL_CHANCE_MINING_STEPS,   "SkillChance.MiningSteps",   75);
		setConfigPos(CONFIG_UINT32_SKILL_CHANCE_SKINNING_STEPS, "SkillChance.SkinningSteps", 75);

		setConfig(CONFIG_BOOL_SKILL_PROSPECTING, "SkillChance.Prospecting", false);
		setConfig(CONFIG_BOOL_SKILL_MILLING,     "SkillChance.Milling",     false);

		setConfigPos(CONFIG_UINT32_SKILL_GAIN_CRAFTING,  "SkillGain.Crafting",  1);
		setConfigPos(CONFIG_UINT32_SKILL_GAIN_DEFENSE,   "SkillGain.Defense",   1);
		setConfigPos(CONFIG_UINT32_SKILL_GAIN_GATHERING, "SkillGain.Gathering", 1);
		setConfig(CONFIG_UINT32_SKILL_GAIN_WEAPON,       "SkillGain.Weapon",    1);

		setConfig(CONFIG_UINT32_MAX_OVERSPEED_PINGS, "MaxOverspeedPings", 2);
		if (getConfig(CONFIG_UINT32_MAX_OVERSPEED_PINGS) != 0 && getConfig(CONFIG_UINT32_MAX_OVERSPEED_PINGS) < 2){
			SLog.outError("MaxOverspeedPings (%i) must be in range 2..infinity (or 0 to disable check). Set to 2.", getConfig(CONFIG_UINT32_MAX_OVERSPEED_PINGS));
			setConfig(CONFIG_UINT32_MAX_OVERSPEED_PINGS, 2);
		}

		setConfig(CONFIG_BOOL_SAVE_RESPAWN_TIME_IMMEDIATLY, "SaveRespawnTimeImmediately", true);
		setConfig(CONFIG_BOOL_WEATHER, "ActivateWeather", true);

		setConfig(CONFIG_BOOL_ALWAYS_MAX_SKILL_FOR_LEVEL, "AlwaysMaxSkillForLevel", false);

		if (configNoReload(reload, CONFIG_UINT32_EXPANSION, "Expansion", MAX_EXPANSION)){
			setConfigMinMax(CONFIG_UINT32_EXPANSION, "Expansion", MAX_EXPANSION, 0, MAX_EXPANSION);
		}

		setConfig(CONFIG_UINT32_CHATFLOOD_MESSAGE_COUNT, "ChatFlood.MessageCount", 10);
		setConfig(CONFIG_UINT32_CHATFLOOD_MESSAGE_DELAY, "ChatFlood.MessageDelay", 1);
		setConfig(CONFIG_UINT32_CHATFLOOD_MUTE_TIME,     "ChatFlood.MuteTime", 10);

		setConfig(CONFIG_BOOL_EVENT_ANNOUNCE, "Event.Announce", false);

		setConfig(CONFIG_UINT32_CREATURE_FAMILY_ASSISTANCE_DELAY, "CreatureFamilyAssistanceDelay", 1500);
		setConfig(CONFIG_UINT32_CREATURE_FAMILY_FLEE_DELAY,       "CreatureFamilyFleeDelay",       7000);

		setConfig(CONFIG_UINT32_WORLD_BOSS_LEVEL_DIFF, "WorldBossLevelDiff", 3);

		// note: disable value (-1) will assigned as 0xFFFFFFF, to prevent overflow at calculations limit it to max possible player level MAX_LEVEL(100)
		setConfig(CONFIG_UINT32_QUEST_LOW_LEVEL_HIDE_DIFF, "Quests.LowLevelHideDiff", 4);
		if (getConfig(CONFIG_UINT32_QUEST_LOW_LEVEL_HIDE_DIFF) > MAX_LEVEL){
			setConfig(CONFIG_UINT32_QUEST_LOW_LEVEL_HIDE_DIFF, MAX_LEVEL);
		}
		setConfig(CONFIG_UINT32_QUEST_HIGH_LEVEL_HIDE_DIFF, "Quests.HighLevelHideDiff", 7);
		if (getConfig(CONFIG_UINT32_QUEST_HIGH_LEVEL_HIDE_DIFF) > MAX_LEVEL){
			setConfig(CONFIG_UINT32_QUEST_HIGH_LEVEL_HIDE_DIFF, MAX_LEVEL);
		}

		setConfigMinMax(CONFIG_UINT32_QUEST_DAILY_RESET_HOUR, "Quests.Daily.ResetHour", 6, 0, 23);
		setConfigMinMax(CONFIG_UINT32_QUEST_WEEKLY_RESET_WEEK_DAY, "Quests.Weekly.ResetWeekDay", 3, 0, 6);
		setConfigMinMax(CONFIG_UINT32_QUEST_WEEKLY_RESET_HOUR, "Quests.Weekly.ResetHour", 6, 0 , 23);

		setConfig(CONFIG_BOOL_QUEST_IGNORE_RAID, "Quests.IgnoreRaid", false);

		setConfig(CONFIG_BOOL_DETECT_POS_COLLISION, "DetectPosCollision", true);

		setConfig(CONFIG_BOOL_RESTRICTED_LFG_CHANNEL,      "Channel.RestrictedLfg", true);
		setConfig(CONFIG_BOOL_SILENTLY_GM_JOIN_TO_CHANNEL, "Channel.SilentlyGMJoin", false);

		setConfig(CONFIG_BOOL_TALENTS_INSPECTING,           "TalentsInspecting", true);
		setConfig(CONFIG_BOOL_CHAT_FAKE_MESSAGE_PREVENTING, "ChatFakeMessagePreventing", false);

		setConfig(CONFIG_UINT32_CHAT_STRICT_LINK_CHECKING_SEVERITY, "ChatStrictLinkChecking.Severity", 0);
		setConfig(CONFIG_UINT32_CHAT_STRICT_LINK_CHECKING_KICK,     "ChatStrictLinkChecking.Kick", 0);

		setConfig(CONFIG_BOOL_CORPSE_EMPTY_LOOT_SHOW,      "Corpse.EmptyLootShow", true);
		setConfigPos(CONFIG_UINT32_CORPSE_DECAY_NORMAL,    "Corpse.Decay.NORMAL",    300);
		setConfigPos(CONFIG_UINT32_CORPSE_DECAY_RARE,      "Corpse.Decay.RARE",      900);
		setConfigPos(CONFIG_UINT32_CORPSE_DECAY_ELITE,     "Corpse.Decay.ELITE",     600);
		setConfigPos(CONFIG_UINT32_CORPSE_DECAY_RAREELITE, "Corpse.Decay.RAREELITE", 1200);
		setConfigPos(CONFIG_UINT32_CORPSE_DECAY_WORLDBOSS, "Corpse.Decay.WORLDBOSS", 3600);

		setConfig(CONFIG_INT32_DEATH_SICKNESS_LEVEL, "Death.SicknessLevel", 11);

		setConfig(CONFIG_BOOL_DEATH_CORPSE_RECLAIM_DELAY_PVP, "Death.CorpseReclaimDelay.PvP", true);
		setConfig(CONFIG_BOOL_DEATH_CORPSE_RECLAIM_DELAY_PVE, "Death.CorpseReclaimDelay.PvE", true);
		setConfig(CONFIG_BOOL_DEATH_BONES_WORLD,              "Death.Bones.World", true);
		setConfig(CONFIG_BOOL_DEATH_BONES_BG_OR_ARENA,        "Death.Bones.BattlegroundOrArena", true);

		setConfig(CONFIG_FLOAT_THREAT_RADIUS, "ThreatRadius", 100.0f);

		// always use declined names in the russian client
		if (getConfig(CONFIG_UINT32_REALM_ZONE) == REALM_ZONE_RUSSIAN){
			setConfig(CONFIG_BOOL_DECLINED_NAMES_USED, true);
		}else{
			setConfig(CONFIG_BOOL_DECLINED_NAMES_USED, "DeclinedNames", false);
		}

		setConfig(CONFIG_BOOL_BATTLEGROUND_CAST_DESERTER,                  "Battleground.CastDeserter", true);
		setConfigMinMax(CONFIG_UINT32_BATTLEGROUND_QUEUE_ANNOUNCER_JOIN,   "Battleground.QueueAnnouncer.Join", 0, 0, 2);
		setConfig(CONFIG_BOOL_BATTLEGROUND_QUEUE_ANNOUNCER_START,          "Battleground.QueueAnnouncer.Start", false);
		setConfig(CONFIG_UINT32_BATTLEGROUND_INVITATION_TYPE,              "Battleground.InvitationType", 0);
		setConfig(CONFIG_UINT32_BATTLEGROUND_PREMATURE_FINISH_TIMER,       "BattleGround.PrematureFinishTimer", 5 * MINUTE * IN_MILLISECONDS);
		setConfig(CONFIG_UINT32_BATTLEGROUND_PREMADE_GROUP_WAIT_FOR_MATCH, "BattleGround.PremadeGroupWaitForMatch", 30 * MINUTE * IN_MILLISECONDS);
		setConfig(CONFIG_UINT32_ARENA_MAX_RATING_DIFFERENCE,               "Arena.MaxRatingDifference", 150);
		setConfig(CONFIG_UINT32_ARENA_RATING_DISCARD_TIMER,                "Arena.RatingDiscardTimer", 10 * MINUTE * IN_MILLISECONDS);
		setConfig(CONFIG_BOOL_ARENA_AUTO_DISTRIBUTE_POINTS,                "Arena.AutoDistributePoints", false);
		setConfig(CONFIG_UINT32_ARENA_AUTO_DISTRIBUTE_INTERVAL_DAYS,       "Arena.AutoDistributeInterval", 7);
		setConfig(CONFIG_BOOL_ARENA_QUEUE_ANNOUNCER_JOIN,                  "Arena.QueueAnnouncer.Join", false);
		setConfig(CONFIG_BOOL_ARENA_QUEUE_ANNOUNCER_EXIT,                  "Arena.QueueAnnouncer.Exit", false);
		setConfig(CONFIG_UINT32_ARENA_SEASON_ID,                           "Arena.ArenaSeason.ID", 1);
		setConfig(CONFIG_UINT32_ARENA_SEASON_PREVIOUS_ID,                  "Arena.ArenaSeasonPrevious.ID", 0);
		setConfigMin(CONFIG_INT32_ARENA_STARTRATING,                       "Arena.StartRating", -1, -1);
		setConfigMin(CONFIG_INT32_ARENA_STARTPERSONALRATING,               "Arena.StartPersonalRating", -1, -1);
		
		setConfig(CONFIG_BOOL_OFFHAND_CHECK_AT_TALENTS_RESET, "OffhandCheckAtTalentsReset", false);

		setConfig(CONFIG_BOOL_KICK_PLAYER_ON_BAD_PACKET, "Network.KickOnBadPacket", false);

		if(int clientCacheId = SConfig.getIntDefault("ClientCacheVersion", 0)){
			// overwrite DB/old value
			if(clientCacheId > 0){
				setConfig(CONFIG_UINT32_CLIENTCACHE_VERSION, clientCacheId);
				SLog.outString("Client cache version set to: %u", clientCacheId);
			}else{
				SLog.outError("ClientCacheVersion can't be negative %d, ignored.", clientCacheId);
			}
		}

		setConfig(CONFIG_UINT32_INSTANT_LOGOUT, "InstantLogout", SEC_MODERATOR);

		setConfigMin(CONFIG_UINT32_GUILD_EVENT_LOG_COUNT, "Guild.EventLogRecordsCount", GUILD_EVENTLOG_MAX_RECORDS, GUILD_EVENTLOG_MAX_RECORDS);
		setConfigMin(CONFIG_UINT32_GUILD_BANK_EVENT_LOG_COUNT, "Guild.BankEventLogRecordsCount", GUILD_BANK_MAX_LOGS, GUILD_BANK_MAX_LOGS);

		setConfig(CONFIG_UINT32_TIMERBAR_FATIGUE_GMLEVEL, "TimerBar.Fatigue.GMLevel", SEC_CONSOLE);
		setConfig(CONFIG_UINT32_TIMERBAR_FATIGUE_MAX,     "TimerBar.Fatigue.Max", 60);
		setConfig(CONFIG_UINT32_TIMERBAR_BREATH_GMLEVEL,  "TimerBar.Breath.GMLevel", SEC_CONSOLE);
		setConfig(CONFIG_UINT32_TIMERBAR_BREATH_MAX,      "TimerBar.Breath.Max", 180);
		setConfig(CONFIG_UINT32_TIMERBAR_FIRE_GMLEVEL,    "TimerBar.Fire.GMLevel", SEC_CONSOLE);
		setConfig(CONFIG_UINT32_TIMERBAR_FIRE_MAX,        "TimerBar.Fire.Max", 1);

		setConfig(CONFIG_BOOL_PET_UNSUMMON_AT_MOUNT,      "PetUnsummonAtMount", true);

		_visibleUnitGreyDistance = SConfig.getFloatDefault("Visibility.Distance.Grey.Unit", 1);
		if(_visibleUnitGreyDistance >  MAX_VISIBILITY_DISTANCE){
			SLog.outError("Visibility.Distance.Grey.Unit can't be greater %f",MAX_VISIBILITY_DISTANCE);
			_visibleUnitGreyDistance = MAX_VISIBILITY_DISTANCE;
		}
		_visibleObjectGreyDistance = SConfig.getFloatDefault("Visibility.Distance.Grey.Object", 10);
		if(_visibleObjectGreyDistance >  MAX_VISIBILITY_DISTANCE){
			SLog.outError("Visibility.Distance.Grey.Object can't be greater %f",MAX_VISIBILITY_DISTANCE);
			_visibleObjectGreyDistance = MAX_VISIBILITY_DISTANCE;
		}

		//visibility on continents
		_maxVisibleDistanceOnContinents      = SConfig.getFloatDefault("Visibility.Distance.Continents",     DEFAULT_VISIBILITY_DISTANCE);
		if(_maxVisibleDistanceOnContinents < 45*getConfig(CONFIG_FLOAT_RATE_CREATURE_AGGRO)){
			SLog.outError("Visibility.Distance.Continents can't be less max aggro radius %f", 45*getConfig(CONFIG_FLOAT_RATE_CREATURE_AGGRO));
			_maxVisibleDistanceOnContinents = 45*getConfig(CONFIG_FLOAT_RATE_CREATURE_AGGRO);
		}else if(_maxVisibleDistanceOnContinents + _visibleUnitGreyDistance >  MAX_VISIBILITY_DISTANCE){
			SLog.outError("Visibility.Distance.Continents can't be greater %f",MAX_VISIBILITY_DISTANCE - _visibleUnitGreyDistance);
			_maxVisibleDistanceOnContinents = MAX_VISIBILITY_DISTANCE - _visibleUnitGreyDistance;
		}

		//visibility in instances
		_maxVisibleDistanceInInstances = SConfig.getFloatDefault("Visibility.Distance.Instances", DEFAULT_VISIBILITY_INSTANCE);
		if(_maxVisibleDistanceInInstances < 45*getConfig(CONFIG_FLOAT_RATE_CREATURE_AGGRO)){
			SLog.outError("Visibility.Distance.Instances can't be less max aggro radius %f",45*getConfig(CONFIG_FLOAT_RATE_CREATURE_AGGRO));
			_maxVisibleDistanceInInstances = 45*getConfig(CONFIG_FLOAT_RATE_CREATURE_AGGRO);
		}else if(_maxVisibleDistanceInInstances + _visibleUnitGreyDistance >  MAX_VISIBILITY_DISTANCE){
			SLog.outError("Visibility.Distance.Instances can't be greater %f",MAX_VISIBILITY_DISTANCE - _visibleUnitGreyDistance);
			_maxVisibleDistanceInInstances = MAX_VISIBILITY_DISTANCE - _visibleUnitGreyDistance;
		}

		//visibility in BG/Arenas
		_maxVisibleDistanceInBGArenas = SConfig.getFloatDefault("Visibility.Distance.BGArenas", DEFAULT_VISIBILITY_BGARENAS);
		if(_maxVisibleDistanceInBGArenas < 45*getConfig(CONFIG_FLOAT_RATE_CREATURE_AGGRO)){
			SLog.outError("Visibility.Distance.BGArenas can't be less max aggro radius %f",45*getConfig(CONFIG_FLOAT_RATE_CREATURE_AGGRO));
			_maxVisibleDistanceInBGArenas = 45*getConfig(CONFIG_FLOAT_RATE_CREATURE_AGGRO);
		}else if(_maxVisibleDistanceInBGArenas + _visibleUnitGreyDistance >  MAX_VISIBILITY_DISTANCE){
			SLog.outError("Visibility.Distance.BGArenas can't be greater %f",MAX_VISIBILITY_DISTANCE - _visibleUnitGreyDistance);
			_maxVisibleDistanceInBGArenas = MAX_VISIBILITY_DISTANCE - _visibleUnitGreyDistance;
		}

		_maxVisibleDistanceForObject    = SConfig.getFloatDefault("Visibility.Distance.Object",   DEFAULT_VISIBILITY_DISTANCE);
		if(_maxVisibleDistanceForObject < INTERACTION_DISTANCE){
			SLog.outError("Visibility.Distance.Object can't be less max aggro radius %f",float(INTERACTION_DISTANCE));
			_maxVisibleDistanceForObject = INTERACTION_DISTANCE;
		}else if(_maxVisibleDistanceForObject + _visibleObjectGreyDistance >  MAX_VISIBILITY_DISTANCE){
			SLog.outError("Visibility.Distance.Object can't be greater %f",MAX_VISIBILITY_DISTANCE-_visibleObjectGreyDistance);
			_maxVisibleDistanceForObject = MAX_VISIBILITY_DISTANCE - _visibleObjectGreyDistance;
		}
		_maxVisibleDistanceInFlight    = SConfig.getFloatDefault("Visibility.Distance.InFlight",      DEFAULT_VISIBILITY_DISTANCE);
		if(_maxVisibleDistanceInFlight + _visibleObjectGreyDistance > MAX_VISIBILITY_DISTANCE){
			SLog.outError("Visibility.Distance.InFlight can't be greater %f",MAX_VISIBILITY_DISTANCE-_visibleObjectGreyDistance);
			_maxVisibleDistanceInFlight = MAX_VISIBILITY_DISTANCE - _visibleObjectGreyDistance;
		}

		// Load the CharDelete related config options
		setConfigMinMax(CONFIG_UINT32_CHARDELETE_METHOD, "CharDelete.Method", 0, 0, 1);
		setConfigMinMax(CONFIG_UINT32_CHARDELETE_MIN_LEVEL, "CharDelete.MinLevel", 0, 0, getConfig(CONFIG_UINT32_MAX_PLAYER_LEVEL));
		setConfigPos(CONFIG_UINT32_CHARDELETE_KEEP_DAYS, "CharDelete.KeepDays", 30);

		// Read the "Data" directory from the config file
		std::string dataPath = SConfig.getStringDefault("DataDir","./");
		if( dataPath.at(dataPath.length()-1)!='/' && dataPath.at(dataPath.length()-1)!='\\' ){
			dataPath.append("/");
		}

		if(reload){
			if(dataPath!=_dataPath){
				SLog.outError("DataDir option can't be changed at mangosd.conf reload, using current value (%session).",_dataPath.c_str());
			}
		}else{
			_dataPath = dataPath;
			SLog.outString("Using DataDir %session",_dataPath.c_str());
		}

		setConfig(CONFIG_BOOL_VMAP_INDOOR_CHECK, "vmap.enableIndoorCheck", true);
		bool enableLOS = SConfig.getBoolDefault("vmap.enableLOS", false);
		bool enableHeight = SConfig.getBoolDefault("vmap.enableHeight", false);
		std::string ignoreMapIds = SConfig.getStringDefault("vmap.ignoreMapIds", "");
		std::string ignoreSpellIds = SConfig.getStringDefault("vmap.ignoreSpellIds", "");
		VMapFactory::createOrGetVMapManager()->setEnableLineOfSightCalc(enableLOS);
		VMapFactory::createOrGetVMapManager()->setEnableHeightCalc(enableHeight);
		VMapFactory::createOrGetVMapManager()->preventMapsFromBeingUsed(ignoreMapIds.c_str());
		VMapFactory::preventSpellsFromBeingTestedForLoS(ignoreSpellIds.c_str());
		SLog.outString( "WORLD: VMap support included. LineOfSight:%i, getHeight:%i",enableLOS, enableHeight);
		SLog.outString( "WORLD: VMap data directory is: %svmaps",_dataPath.c_str());
		SLog.outString( "WORLD: VMap config keys are: vmap.enableLOS, vmap.enableHeight, vmap.ignoreMapIds, vmap.ignoreSpellIds");

	}

	void World::setPlayerLimit(int limit, bool needUpdate)
	{
		if (limit < -SEC_ADMINISTRATOR){
			limit = -SEC_ADMINISTRATOR;
		}

		// lock update need
		bool update = needUpdate || (limit < 0) != (_playerLimit < 0) || (limit < 0 && _playerLimit < 0 && limit != _playerLimit);

		_playerLimit = limit;

		if (update){
			//SLoginDB.PExecute("UPDATE realmlist SET allowedSecurityLevel = '%u' WHERE id = '%d'",uint8(GetPlayerSecurityLimit()),realmID);
		}
	}

	void World::setConfigPos(ConfigUInt32Values index, char const* fieldname, uint32 defvalue)
	{
		setConfig(index, fieldname, defvalue);
		if (int32(getConfig(index)) < 0){
			SLog.outError("%session (%i) can't be negative. Using %u instead.", fieldname, int32(getConfig(index)), defvalue);
			setConfig(index, defvalue);
		}
	}

	bool World::configNoReload(bool reload, ConfigUInt32Values index, char const* fieldname, uint32 defvalue)
	{
		if (!reload){
			return true;
		}

		uint32 val = SConfig.getIntDefault(fieldname, defvalue);
		if (val != getConfig(index)){
			SLog.outError("%session option can't be changed at mangosd.conf reload, using current value (%u).", fieldname, getConfig(index));
		}
		return false;
	}

	bool World::configNoReload(bool reload, ConfigInt32Values index, char const* fieldname, int32 defvalue)
	{
		if (!reload){
			return true;
		}

		int32 val = SConfig.getIntDefault(fieldname, defvalue);
		if (val != getConfig(index)){
			SLog.outError("%session option can't be changed at mangosd.conf reload, using current value (%i).", fieldname, getConfig(index));
		}

		return false;
	}

	bool World::configNoReload(bool reload, ConfigFloatValues index, char const* fieldname, float defvalue)
	{
		if (!reload){
			return true;
		}

		float val = SConfig.getFloatDefault(fieldname, defvalue);
		if (val != getConfig(index)){
			SLog.outError("%session option can't be changed at mangosd.conf reload, using current value (%f).", fieldname, getConfig(index));
		}
		return false;
	}

	bool World::configNoReload(bool reload, ConfigBoolValues index, char const* fieldname, bool defvalue)
	{
		if (!reload){
			return true;
		}

		bool val = SConfig.getBoolDefault(fieldname, defvalue);
		if (val != getConfig(index)){
			SLog.outError("%session option can't be changed at mangosd.conf reload, using current value (%session).", fieldname, getConfig(index) ? "'true'" : "'false'");
		}

		return false;
	}

	void World::InitResultQueue()
	{
		_resultQueue = new SqlResultQueue;
		SCharacterDB.SetResultQueue(_resultQueue);
	}

	/// Update the game time
	void World::updateGameTime()
	{
		//update the time
		time_t thisTime=time(NULL);
		uint32 elapsed=uint32(thisTime-_gameTime);
		_gameTime=thisTime;

		// if there is a shutdown timer
		if(!_stopEvent&&_shutdownTimer>0&&elapsed>0){
			//and it is overdue,stop the world
			if( _shutdownTimer <= elapsed ){
				if(!(_shutdownMask & SHUTDOWN_MASK_IDLE) || GetActiveAndQueuedSessionCount()==0){
					_stopEvent = true;                         // exist code already set
				}else{
					_shutdownTimer = 1;                        // minimum timer value to wait idle state
				}
			}else{
				//decrease it and if necessary display a shutdown countdown to the users
				_shutdownTimer -= elapsed;
				ShutdownMsg();
			}

		}
	}

	void World::ShutdownMsg(bool show, Player* player)
	{
		// not show messages for idle shutdown mode
		if(_shutdownMask & SHUTDOWN_MASK_IDLE){
			return;
		}
		///- Display a message every 12 hours, hours, 5 minutes, minute, 5 seconds and finally seconds
		if (show ||(_shutdownTimer < 10) ||(_shutdownTimer<30 && (_shutdownTimer % 5 )==0) ||// < 30 sec; every 5 sec
			(_shutdownTimer<5*MINUTE && (_shutdownTimer % MINUTE )==0) ||// < 5 min ; every 1 min
			(_shutdownTimer<30*MINUTE && (_shutdownTimer % (5*MINUTE))==0) ||// < 30 min ; every 5 min
			(_shutdownTimer<12*HOUR   && (_shutdownTimer % HOUR)==0) ||// < 12 h ; every 1 h
			(_shutdownTimer>12*HOUR   && (_shutdownTimer % (12*HOUR) )==0)){// > 12 h ; every 12 h
			std::string str = secsToTimeString(_shutdownTimer);

			ServerMessageType msgid = (_shutdownMask & SHUTDOWN_MASK_RESTART) ? SERVER_MSG_RESTART_TIME : SERVER_MSG_SHUTDOWN_TIME;
			//SendServerMessage(msgid,str.c_str(),player);
			SLog.debugLog("Server is %session in %session",(_shutdownMask & SHUTDOWN_MASK_RESTART ? "restart" : "shutting down"),str.c_str());

		}
	}


	void World::Update(uint32 deltaT)
	{
		// Update the different timers
		for(int i = 0; i < WUPDATE_COUNT; ++i){
			if (_timers[i].GetCurrent()>=0){
				_timers[i].Update(deltaT);
			}else{
				_timers[i].SetCurrent(0);
			}
		}

		
		// Update the game time and check for shutdown time
		updateGameTime();

		/// Handle daily quests reset time
		if(_gameTime>_nextDailyQuestReset){
			ResetDailyQuests();
		}

		/// Handle weekly quests reset time
		if(_gameTime>_nextWeeklyQuestReset){
			ResetWeeklyQuests();
		}

		 /// <ul><li> Handle auctions when the timer has passed
		if(_timers[WUPDATE_AUCTIONS].Passed()){
			_timers[WUPDATE_AUCTIONS].Reset();
			//Update mails
			if (++_mailTimer > _mailTimerExpires){
				_mailTimer = 0;
				SObjectMgr.ReturnOrDeleteOldMails(true);
			}

			// Handle expired auctions
			SAuctionMgr.Update();
		}

		/// <li> Handle session updates when the timer has passed
		if (_timers[WUPDATE_SESSIONS].Passed()){
			_timers[WUPDATE_SESSIONS].Reset();

			UpdateSessions(deltaT);
		}

		/// <li> Handle weather updates when the timer has passed
		if (_timers[WUPDATE_WEATHERS].Passed()){
			_timers[WUPDATE_WEATHERS].Reset();

			// Send an update signal to Weather objects
			WeatherMap::iterator itr, next;
			for (itr = _weathers.begin(); itr != _weathers.end(); itr = next){
				next = itr;
				++next;

				// and remove Weather objects for zones with no player //As interval > WorldTick
				if(!itr->second->Update(_timers[WUPDATE_WEATHERS].GetInterval())){
					delete itr->second;
					_weathers.erase(itr);
				}
			}
		}

		/// <li> Update uptime table
		if (_timers[WUPDATE_UPTIME].Passed()){
			uint32 tmpDiff = uint32(_gameTime - _startTime);
			uint32 maxClientsNum = GetMaxActiveSessionCount();

			_timers[WUPDATE_UPTIME].Reset();
			SLoginDB.PExecute("UPDATE uptime SET uptime = %u, maxplayers = %u WHERE realmid = %u AND starttime = " UI64FMTD, tmpDiff, maxClientsNum, realmID, uint64(_startTime));
		}

		/// <li> Handle all other objects
		if (_timers[WUPDATE_OBJECTS].Passed()){
			_timers[WUPDATE_OBJECTS].Reset();
			// Update objects when the timer has passed (maps, transport, creatures,...)
			SMapMgr.Update(deltaT);                // As interval = 0

			SBattleGroundMgr.Update(deltaT);
		}

		// Delete all characters which have been deleted X days before
		if (_timers[WUPDATE_DELETECHARS].Passed()){
			_timers[WUPDATE_DELETECHARS].Reset();
			Player::DeleteOldCharacters();
		}

		// execute callbacks from sql queries that were queued recently
		UpdateResultQueue();

		// Erase corpses once every 20 minutes
		if (_timers[WUPDATE_CORPSES].Passed()){
			_timers[WUPDATE_CORPSES].Reset();

			SObjectAccessor.RemoveOldCorpses();
		}

		// Process Game events when necessary
		if (_timers[WUPDATE_EVENTS].Passed()){
			_timers[WUPDATE_EVENTS].Reset();                   // to give time for Update() to be processed
			uint32 nextGameEvent = SGameEventMgr.Update();
			_timers[WUPDATE_EVENTS].SetInterval(nextGameEvent);
			_timers[WUPDATE_EVENTS].Reset();
		}

		/// </ul>
		// Move all creatures with "delayed move" and remove and delete all objects with "delayed remove"
		SMapMgr.RemoveAllObjectsInRemoveList();

		// update the instance reset times
		SInstanceSaveMgr.Update();

		// And last, but not least handle the issued cli commands
		ProcessCliCommands();//command line interface
	}

	void World::UpdateSessions(uint32 deltaT)
	{
		 ///- Add new sessions
		WorldSession* session;
		while(_sessionQueueAdd.next(session)){
			addWorldSession(session);
		}

		///- Then send an update signal to remaining ones
		for (SessionMap::iterator itr = _sessions.begin(), next; itr != _sessions.end(); itr = next){
			next = itr;
			++next;
			///- and remove not active sessions from the list.As interval = 0
			if(!itr->second->Update(deltaT)){
				RemoveQueuedPlayer(itr->second);
				delete itr->second;
				_sessions.erase(itr);
			}
		}
	}

	void World::addWorldSession(WorldSession* session)
	{
		if(session){
			return;
		}

		//NOTE - Still there is race condition in WorldSession* being used in the Sockets
		///- kick already loaded player with same account (if any) and remove session
		///- if player is in loading and want to load again, return
		if (!RemoveSession(session->GetAccountId())){
			session->KickPlayer();
			delete session;// session not added yet in session list, so not listed in queue
			return;
		}

		// decrease session counts only at not reconnection case
		bool decrease_session = true;

		// if session already exist, prepare to it deleting at next world update
		// NOTE - KickPlayer() should be called on "old" in RemoveSession()
		{
			SessionMap::const_iterator old = _sessions.find(session->GetAccountId());

			if(old != _sessions.end()){
				// prevent decrease sessions count if session queued
				if(RemoveQueuedPlayer(old->second)){
					decrease_session = false;
				}
				// not remove replaced session form queue if listed
				delete old->second;
			}
		}

		_sessions[session->GetAccountId()] = session;

		uint32 Sessions = GetActiveAndQueuedSessionCount();
		uint32 pLimit = GetPlayerAmountLimit();
		uint32 QueueSize = GetQueueSize();                     //number of players in the queue

		//so we don't count the user trying to
		//login as a session and queue the socket that we are using
		if(decrease_session){
			--Sessions;
		}

		if (pLimit > 0 && Sessions >= pLimit && session->GetSecurity() == SEC_PLAYER ){
			AddQueuedPlayer(session);
			UpdateMaxSessionCounters();
			SLog.detailLog("PlayerQueue: Account id %u is in Queue Position (%u).", session->GetAccountId (), ++QueueSize);
			return;
		}

		WorldPacket packet(SMSG_AUTH_RESPONSE, 1 + 4 + 1 + 4 + 1);
		packet << uint8 (AUTH_OK);
		packet << uint32 (0); // BillingTimeRemaining
		packet << uint8 (0); // BillingPlanFlags
		packet << uint32 (0); // BillingTimeRested
		packet << uint8 (session->Expansion()); // 0 - normal, 1 - TBC, must be set in database manually for each account
		session->SendPacket(&packet);

		session->SendAddonsInfo();

		WorldPacket pkt(SMSG_CLIENTCACHE_VERSION, 4);
		pkt << uint32(getConfig(CONFIG_UINT32_CLIENTCACHE_VERSION));
		session->SendPacket(&pkt);

		session->SendTutorialsData();
		UpdateMaxSessionCounters();

		// Updates the population
		if (pLimit > 0){
			float population = float(GetActiveSessionCount());        // updated number of users on the server
			population /= pLimit;
			population *= 2;
			SLoginDB.PExecute ("UPDATE realmlist SET population = '%f' WHERE id = '%d'", population, realmID);
			SLog.detailLog("Server Population (%f).", population);
		}

	}

	
	void World::UpdateMaxSessionCounters()
	{
		_maxActiveSessionCount = std::max(_maxActiveSessionCount,uint32(_sessions.size()-_queuedPlayer.size()));
		_maxQueuedSessionCount = std::max(_maxQueuedSessionCount,uint32(_queuedPlayer.size()));
	}


	/// Remove a given session
	bool World::RemoveSession(uint32 id)
	{
		///- Find the session, kick the user, but we can't delete session at this moment to prevent iterator invalidation
		SessionMap::const_iterator itr = _sessions.find(id);

		if(itr != _sessions.end() && itr->second){
			if (itr->second->PlayerLoading()){
				return false;
			}
			itr->second->KickPlayer();
		}

		return true;
	}

	bool World::RemoveQueuedPlayer(WorldSession* sess)
	{
		return false;
		/*
		// sessions count including queued to remove (if removed_session set)
		uint32 sessions = GetActiveSessionCount();

		uint32 position = 1;
		Queue::iterator iter = m_QueuedPlayer.begin();

		// search to remove and count skipped positions
		bool found = false;

		for(;iter != m_QueuedPlayer.end(); ++iter, ++position)
		{
			if(*iter==sess)
			{
				sess->SetInQueue(false);
				iter = m_QueuedPlayer.erase(iter);
				found = true;                                   // removing queued session
				break;
			}
		}

		// iter point to next socked after removed or end()
		// position store position of removed socket and then new position next socket after removed

		// if session not queued then we need decrease sessions count
		if(!found && sessions)
			--sessions;

		// accept first in queue
		if( (!m_playerLimit || (int32)sessions < m_playerLimit) && !m_QueuedPlayer.empty() )
		{
			WorldSession* pop_sess = m_QueuedPlayer.front();
			pop_sess->SetInQueue(false);
			pop_sess->SendAuthWaitQue(0);
			pop_sess->SendAddonsInfo();

			WorldPacket pkt(SMSG_CLIENTCACHE_VERSION, 4);
			pkt << uint32(getConfig(CONFIG_UINT32_CLIENTCACHE_VERSION));
			pop_sess->SendPacket(&pkt);

			pop_sess->SendAccountDataTimes(GLOBAL_CACHE_MASK);
			pop_sess->SendTutorialsData();

			m_QueuedPlayer.pop_front();

			// update iter to point first queued socket or end() if queue is empty now
			iter = m_QueuedPlayer.begin();
			position = 1;
		}

		// update position from iter to end()
		// iter point to first not updated socket, position store new position
		for(; iter != m_QueuedPlayer.end(); ++iter, ++position)
			(*iter)->SendAuthWaitQue(position);

		return found;
		*/
	}

	void World::AddQueuedPlayer(WorldSession* session)
	{
		assert(!"Not implemented");
		/*
		 sess->SetInQueue(true);
    m_QueuedPlayer.push_back (sess);

    // The 1st SMSG_AUTH_RESPONSE needs to contain other info too.
    WorldPacket packet (SMSG_AUTH_RESPONSE, 1 + 4 + 1 + 4 + 1 + 4 + 1);
    packet << uint8 (AUTH_WAIT_QUEUE);
    packet << uint32 (0);                                   // BillingTimeRemaining
    packet << uint8 (0);                                    // BillingPlanFlags
    packet << uint32 (0);                                   // BillingTimeRested
    packet << uint8 (sess->Expansion());                    // 0 - normal, 1 - TBC, must be set in database manually for each account
    packet << uint32(GetQueuePos (sess));                   // position in queue
    packet << uint8(0);                                     // unk 3.3.0
    sess->SendPacket (&packet);
	*/
	}

	void World::KickAll()
	{
		assert(!"Not implemented");
	}


}
